import axios from 'axios'
import { ElMessage } from 'element-plus'
import { getToken } from '@/utils/cookie'
import GlobalLoad from '@/utils/loading'
import useStore from '@/store'
import router from '@/router'
import { OpenMessage } from '@/utils'

// 如果某个请求不想打开全局 loading，那么肯定也不想页面自动出现一个请求成功的弹框
// 所以创建了两个 axios 实例，一个会自动弹出请求成功的弹框，另一个不会自动出现弹框
// 这里抽象出来一些公共的变量与方法，给两个 axios 实例使用。暂时先这样写
const BASE_URL = import.meta.env.VITE_APP_BASE_API
const TIMEOUT = 60000
const WITH_CREDENTIALS = true

const onFulfilled = (config) => {
  // 设置请求头携带Token
  config.headers['XiuMuToken'] = getToken()
  return config
}

const onRejected = (error) => {
  // do something with request error
  console.log(error) // for debug
  return Promise.reject(error)
}

const responseOnFulfilled = (data, openElMessage) => {
  GlobalLoad.hide()
  const { code, msg, operateType } = data
  // 处理返回值
  if (code !== 200) {
    // 弹出错误提示
    OpenMessage.openElMessage(false, msg, operateType)
    // 判断未登录，跳转登录页面
    if (code === 300) {
      const { user } = useStore()
      user.resetToken().then()
      router.push('/login').then()
    }
    return Promise.reject(data)
  } else {
    // 弹出成功提示
    if (openElMessage) {
      OpenMessage.openElMessage(true, msg, operateType)
    }
    return data
  }
}

const responseOnRejected = (error) => {
  GlobalLoad.hide()
  ElMessage.error('网络错误！')
  return Promise.reject(error)
}

// create an axios instance
const service = axios.create({
  baseURL: BASE_URL, // url = base url + request url
  timeout: TIMEOUT, // request timeout
  withCredentials: WITH_CREDENTIALS,
})

// request interceptor
service.interceptors.request.use(onFulfilled, onRejected)

// response interceptor
service.interceptors.response.use(({ config, data }) => {
  return responseOnFulfilled(data, true)
}, responseOnRejected)

// 创建一个不自动打开弹框的axios实例
const serviceNotOpenElMessage = axios.create({
  baseURL: BASE_URL, // url = base url + request url
  timeout: TIMEOUT, // request timeout
  withCredentials: WITH_CREDENTIALS,
})

// request interceptor
serviceNotOpenElMessage.interceptors.request.use(onFulfilled, onRejected)

// response interceptor
serviceNotOpenElMessage.interceptors.response.use(({ config, data }) => {
  return responseOnFulfilled(data, false)
}, responseOnRejected)

/**
 * 封装请求方式
 * 方法命名规范：第一个单词是请求方式，第二个单词是请求参数类型
 */
export default class Http {
  /**
   * get请求, 不可以将参数放在 body 中，参数会被忽略
   *
   * @param url     请求地址
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static get(url, params, loading = true) {
    return this.request(url, 'get', null, params, loading)
  }

  /**
   * post请求
   * @param url     请求地址
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static postParams(url, params, loading = true) {
    return this.request(url, 'post', null, params, loading)
  }

  /**
   * post请求
   * @param url     请求地址
   * @param data    请求 body, json格式，放在请求体传输
   * @param loading 是否打开全局加载 loading 页面
   */
  static postData(url, data, loading = true) {
    return this.request(url, 'post', data, null, loading)
  }

  /**
   * post请求
   * @param url     请求地址
   * @param data    请求 body, json格式，放在请求体传输
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static post(url, data, params, loading = true) {
    return this.request(url, 'post', data, params, loading)
  }

  /**
   * put请求
   * @param url     请求地址
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static putParams(url, params, loading = true) {
    return this.request(url, 'put', null, params, loading)
  }

  /**
   * put请求
   * @param url     请求地址
   * @param data    请求 body, json格式，放在请求体传输
   * @param loading 是否打开全局加载 loading 页面
   */
  static putData(url, data, loading = true) {
    return this.request(url, 'put', data, null, loading)
  }

  /**
   * put请求
   * @param url     请求地址
   * @param data    请求 body, json格式，放在请求体传输
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static put(url, data, params, loading = true) {
    return this.request(url, 'put', data, params, loading)
  }

  /**
   * delete请求
   * @param url     请求地址
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static deleteParams(url, params, loading = true) {
    return this.request(url, 'delete', null, params, loading)
  }

  /**
   * delete请求
   * @param url     请求地址
   * @param data    请求 body, json格式，放在请求体传输
   * @param loading 是否打开全局加载 loading 页面
   */
  static deleteData(url, data, loading = true) {
    return this.request(url, 'delete', data, null, loading)
  }

  /**
   * delete请求
   * @param url     请求地址
   * @param data    请求 body, json格式，放在请求体传输
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static delete(url, data, params, loading = true) {
    return this.request(url, 'delete', data, params, loading)
  }

  /**
   * 请求
   * @param url     请求地址
   * @param method  请求方式 get, post, put, delete
   * @param data    请求 body, json格式，放在请求体传输
   * @param params  请求参数, 显示在 URL 上的参数
   * @param loading 是否打开全局加载 loading 页面
   */
  static request(url, method, data, params, loading = true) {
    if (loading) {
      GlobalLoad.show()
      return service({
        url,
        method,
        data,
        params,
      })
    } else {
      GlobalLoad.timePlus()
      return serviceNotOpenElMessage({
        url,
        method,
        data,
        params,
      })
    }
  }

  /**
   * 文件上传请求
   * @param url      请求地址
   * @param formData 利用 FormData 作为文件参数
   * @param loading  是否打开全局加载 loading 页面
   */
  static uploadFile(url, formData, loading = true) {
    if (loading) {
      GlobalLoad.show()
    } else {
      GlobalLoad.timePlus()
    }
    return service({
      url,
      method: 'post',
      data: formData,
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    })
  }
}
